//
// Created by denglibin on 2021/4/7 0007.
//

#include "camera.h"
#include "glm.hpp"
Camera::Camera() {
    cameraPos.x = 0;
    cameraPos.y = 0;
    cameraPos.z = 3.0f;

    cameraFront.x = 0;
    cameraFront.y = 0;
    cameraFront.z = -1.0f; //z轴负方向

    cameraUp.x = 0;
    cameraUp.y = 1.0f;
    cameraUp.z = 0;

    cameraSpeed = 0.1f;
    firstMouse = true;
    fovY = 45.0f;
}
Camera::~Camera() {

}

/**
 * 向前移动
 */
void Camera:: moveFront(){
    glm::vec3 moveScale = cameraFront *cameraSpeed;
    cameraPos +=  moveScale;
}
/**
* 向后移动
*/
void  Camera:: moveBack(){
    glm::vec3 moveScale = -cameraFront *cameraSpeed;
    cameraPos +=  moveScale;
}
/**
* 向左移动
*/
void Camera:: moveLeft(){
    //叉乘得到向左的一个向量
    glm::vec3 leftV = glm::cross(cameraUp, cameraFront);
    glm::normalize(leftV);//标准化
    glm::vec3 moveScale = leftV * cameraSpeed; //移动大小
    cameraPos += moveScale;
}
/**
* 向右移动
*/
void Camera:: moveRight(){
    //叉乘得到向左的一个向量
    glm::vec3 rightV = glm::cross(cameraFront, cameraUp);
    glm::normalize(rightV);//标准化
    glm::vec3 moveScale = rightV * cameraSpeed; //移动大小
    cameraPos += moveScale;
}

/**
 * 向上移动
 */
void Camera:: moveUp(){
    glm::vec3 moveScale = cameraUp *cameraSpeed;
    cameraPos +=  moveScale;
}

/**
 * 向下移动
 */
void Camera:: moveDown(){
    glm::vec3 moveScale = -cameraUp *cameraSpeed;
    cameraPos +=  moveScale;
}
/**
     * 根据鼠标位置改变 方向
     * @param x
     * @param y
     */
void Camera::mouseDirection(double x, double y){
    /**
    * 如果你现在运行代码，你会发现在窗口第一次获取焦点的时候摄像机会突然跳一下。这个问题产生的原因是，在你的鼠标移动进窗口的那一刻，
    * 鼠标回调函数就会被调用，这时候的xpos和ypos会等于鼠标刚刚进入屏幕的那个位置。这通常是一个距离屏幕中心很远的地方，因而产生一个很大的偏移量，
    * 所以就会跳了。我们可以简单的使用一个bool变量检验我们是否是第一次获取鼠标输入，如果是，那么我们先把鼠标的初始位置更新为xpos和ypos值，这样就能解决这个问题
    **/
    if(firstMouse){
        lastX = (float )x;
        lastY = (float )y;
        firstMouse = false;
    }

    float x_offset = (float )x - lastX;
    float y_offset = -((float)y - lastY); //鼠标往上移动，屏幕的y坐标减小，而世界坐标中，网上是y增大，所以取反

    lastX = (float )x;
    lastY = (float )y;

    float sensitivity = 0.05f;//灵敏度
    x_offset *= sensitivity;
    y_offset *= sensitivity;

    yaw += x_offset;
    pitch += y_offset;
    //对于俯仰角，要让用户不能看向高于89度的地方（在90度时视角会发生逆转，所以我们把89度作为极限），同样也不允许小于-89度。这样能够保证用户只能看到天空或脚下，但是不能超越这个限制
    if(pitch > 89.0f)
        pitch =  89.0f;
    if(pitch < -89.0f)
        pitch = -89.0f;
    //注意我们没有给偏航角设置限制，这是因为我们不希望限制用户的水平旋转。当然，给偏航角设置限制也很容易，如果你愿意可以自己实现。
    if(yaw > 89.0f)
        yaw =  89.0f;


    //通过俯仰角和偏航角来计算以得到真正的方向向量

    cameraFront[0] = cosf((float)(pitch/180.0f * M_PI)) * sinf(float(yaw/180.0f * M_PI)) ;
    cameraFront[1] = sinf((float)(pitch/180.0f * M_PI));
    cameraFront[2] = cosf((float)(pitch/180.0f * M_PI)) * cosf((float)(yaw/180.0f * M_PI)) * (-1); //取反表示看向z轴负方向
    glm::normalize(cameraFront); //标准化
}
/**
    * 鼠标滚轮滚动改变视角
    * @param x_offset
    * @param y_offset
    */
void Camera::scrollFov( double x_offset, double y_offset){
    float sensitivity = 1.0f;//灵敏度
    y_offset *= sensitivity;
    if(fovY >= 1.0f && fovY <= 45.0f)
        fovY -= (float)y_offset;
    if(fovY <= 1.0f)
        fovY = 1.0f;
    if(fovY >= 45.0f)
        fovY = 45.0f;
}